<?php
// php.exe E:\qh\speed\workerman.php
error_reporting(0);

use Workerman\Protocols\Http;
use Workerman\Worker;

define('APP_DIR', __DIR__);
define('APP_EVN', 'workerman');
define('APP_PORT', 10087);
require(APP_DIR . '/lib/core.php');
$http_worker = new Worker("http://0.0.0.0:" . APP_PORT);
echo "
     _______   ______   ___   ___    .______     ______     ______   .___________.
    |   ____| /  __  \  \  \ /  /    |   _  \   /  __  \   /  __  \  |           |
    |  |__   |  |  |  |  \  V  /     |  |_)  | |  |  |  | |  |  |  | `---|  |----`
    |   __|  |  |  |  |   >   <      |   _  <  |  |  |  | |  |  |  |     |  |     
    |  |     |  `--'  |  /  .  \     |  |_)  | |  `--'  | |  `--'  |     |  |     
    |__|      \______/  /__/ \__\    |______/   \______/   \______/      |__|    
                                                                               
                :: Fox Boot V1.1 ::        (workerman:" . Worker::VERSION . ")\n";
echo "open web http://foxboot.v.cnbbx.com:" . APP_PORT . "\n";
// 启动4个进程对外提供服务
$http_worker->count = 4;
Worker::$_OS = OS_TYPE_WINDOWS;
$mimeTypeMap = array();

/**
 * @param $connection Http
 * @param $data
 * @return bool
 */
$http_worker->onMessage = function ($connection, $data) {
    global $GLOBALS, $globals, $app, $sqlLog, $get_one_cache;
    if ($globals == null) {
        $globals = true;
        $_SERVER["HTTP_HOST"] = "app.v.cnbbx.com";
        $GLOBALS += require(APP_DIR . '/config.php');
    }
    $GLOBALS['out_handler'] = function ($html) use ($connection) {
        $connection->send($html);
    };
    initMimeTypeMap();
    $sqlLog = [];
    $get_one_cache = [];
    $app = new core();
    $app->request = array_merge($data['get'], $data['post']);
    $app->cookie = $data['cookie'];
    $app->server = $data['server'];
    $app->header = $app->server;
    $app->response = $connection;
    $app->mothod = "workerMan";
    $REQUEST_URI = str_replace("?" . $app->server['QUERY_STRING'], "", $app->server['REQUEST_URI']);
    Http::header('Server: FoxBoot/v1.0');
    //Swoole静态化ssi支持
    if ($REQUEST_URI == '/favicon.ico') {
        return $app->response->send('');
    } else {
        $filename = APP_DIR . DS . $REQUEST_URI;
        if (file_exists($filename) && is_file($filename)) {
            $cache_time = 60 * 60;
            if (isset($app->server['HTTP_IF_MODIFIED_SINCE'])) {
                $modified_time = $app->server['HTTP_IF_MODIFIED_SINCE'];
                if (strtotime($modified_time) + $cache_time > time()) {
                    $app->response->responseCode(304);
                    return $app->response->send('');
                }
            }
            if (ob_get_contents()) ob_end_clean();
            $ext = pathinfo($filename);
            $checkExt = ['shtml', 'html', 'htm'];
            if (in_array($ext['extension'], $checkExt)) {
                $file_data = file_get_contents($filename, true);
                $pattern = '/' . str_replace(array("<{", "}>"), array('\s*', '\s*'), '<\!\-\-#include\s*virtual\s*="(.+?)"\-\->') . '/i';
                $count = 1;
                while ($count != 0) {
                    preg_match($pattern, $file_data, $match);
                    if (isset($match[1])) {
                        $filename = APP_DIR . DS . $match[1];
                        if (is_file($filename)) {
                            $template = file_get_contents($filename, true);
                        } else {
                            $template = $filename . " file is not find!";
                        }
                        $file_data = preg_replace($pattern, $template, $file_data, 1, $count);
                    } else {
                        $count = 0;
                    }
                }
                return $app->response->send($file_data);
            } else {
                sendFile($connection, $filename);
                return $app->response->send('');

            }
        }
    }
    if (!empty($GLOBALS['rewrite'])) {
        $http_scheme = 'http';
        $http_host = 'foxboot.v.cnbbx.com';
        foreach ($GLOBALS['rewrite'] as $rule => $mapper) {
            if ('/' == $rule) $rule = '/$';
            if (0 !== stripos($rule, $http_scheme)) $rule = $http_scheme . $http_host . '/' . $rule;
            $rule = '/' . str_ireplace(array('\\\\', $http_scheme, '/', '<', '>', '.'), array('', '', '\/', '(?P<', '>[-\.\w]+)', '\.'), $rule) . '/i';
            if (preg_match($rule, $http_scheme . $http_host . $app->server['REQUEST_URI'], $matches)) {
                $route = explode("/", $mapper);
                if (isset($route[2])) {
                    list($app->request['m'], $app->request['c'], $app->request['a']) = $route;
                } else {
                    list($app->request['c'], $app->request['a']) = $route;
                }
                foreach ($matches as $matchkey => $matchval) if (!is_int($matchkey)) $app->request[$matchkey] = $matchval;
                break;
            }
        }
    }
    $app->app_module = isset($app->request['m']) ? strtolower($app->request['m']) : 'home';
    $app->app_controller = isset($app->request['c']) ? strtolower($app->request['c']) : 'main';
    $app->app_action = isset($app->request['a']) ? strtolower($app->request['a']) : 'index';
    unset($app->request['m']);
    unset($app->request['c']);
    unset($app->request['a']);
    $controller_name = str_replace("/", "\\", str_replace("//", "/", str_replace("\\\\", "\\", "app" . DS . $app->app_module . DS . 'controller' . DS . $app->app_controller . 'Control')));
    if (!empty($app->app_module)) if (!is_available_classname($app->app_module)) return err("Err: Module '$app->app_module' is not correct!");
    if (!is_available_classname($app->app_controller)) return err("Err: Controller '$controller_name' is not correct!");
    if (!class_exists($controller_name, true)) return err("Err: Controller '$controller_name' is not exists!");
    if (!method_exists($controller_name, $app->app_action)) return err("Err: Method '$app->app_action' of '$controller_name' is not exists!");
    try {
        $controller_obj = new $controller_name($app);
        $arr = explode('/', $app->server['REQUEST_URI']);
        call_user_func_array(array($controller_obj, $app->app_action), count($arr) > 4 ? array_slice($arr, 4) : array());
        if ($controller_obj->_auto_display) {
            $auto_tpl_name = (empty($app->app_module) ? '' : $app->app_module . DS) . $app->app_controller . '_' . $app->app_action . '.html';
            if (file_exists(APP_DIR . DS . 'app' . DS . 'view' . DS . $auto_tpl_name)) $controller_obj->display($auto_tpl_name);
        }
    } catch (Exception $e) {
        err("error: " . $e->getMessage());
    }
    return $app->response->send('');
};
// 运行worker
Worker::runAll();

function sendFile($connection, $file_path)
{
    global $mimeTypeMap;
    // Check 304.
    $info = \stat($file_path);
    $modified_time = $info ? \date('D, d M Y H:i:s', $info['mtime']) . ' ' . \date_default_timezone_get() : '';
    if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) {
        // Http 304.
        if ($modified_time === $_SERVER['HTTP_IF_MODIFIED_SINCE']) {
            // 304
            Http::header('HTTP/1.1 304 Not Modified');
            // Send nothing but http headers..
            if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") {
                $connection->send('');
            } else {
                $connection->close('');
            }
            return;
        }
    }

    // Http header.
    if ($modified_time) {
        $modified_time = "Last-Modified: $modified_time\r\n";
    }
    $file_size = \filesize($file_path);
    $file_info = \pathinfo($file_path);
    $extension = isset($file_info['extension']) ? $file_info['extension'] : '';
    $file_name = isset($file_info['filename']) ? $file_info['filename'] : '';
    $cache_time = 60 * 60;
    $header = "HTTP/1.1 200 OK\r\n";
    $header .= "Server: FoxBoot/v1.0\r\n";
    $header .= "Expires: " . gmdate("D, d M Y H:i:s", time() + $cache_time) . " GMT\r\n";
    $header .= "Cache-Control: max-age=$cache_time\r\n";
    if (isset($mimeTypeMap[$extension])) {
        $header .= "Content-Type: " . $mimeTypeMap[$extension] . "\r\n";
    } else {
        $header .= "Content-Type: application/octet-stream\r\n"
            . "Content-Disposition: attachment; filename=\"$file_name\"\r\n";
    }
    $header .= "Connection: keep-alive\r\n"
        . $modified_time
        . "Content-Length: $file_size\r\n\r\n";
    $trunk_limit_size = 1024 * 1024;
    if ($file_size < $trunk_limit_size) {
        return $connection->send($header . \file_get_contents($file_path), true);
    }
    $connection->send($header, true);

    // Read file content from disk piece by piece and send to client.
    $connection->fileHandler = \fopen($file_path, 'r');
    $do_write = function () use ($connection) {
        // Send buffer not full.
        while (empty($connection->bufferFull)) {
            // Read from disk.
            $buffer = \fread($connection->fileHandler, 8192);
            // Read eof.
            if ($buffer === '' || $buffer === false) {
                return;
            }
            $connection->send($buffer, true);
        }
    };
    // Send buffer full.
    $connection->onBufferFull = function ($connection) {
        $connection->bufferFull = true;
    };
    // Send buffer drain.
    $connection->onBufferDrain = function ($connection) use ($do_write) {
        $connection->bufferFull = false;
        $do_write();
    };
    $do_write();
}

function initMimeTypeMap()
{
    global $mimeTypeMap;
    $mime_file = APP_DIR . '/lib/mime.types';
    if (!\is_file($mime_file)) {
        logs("$mime_file mime.type file not fond");
        return;
    }
    $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES);
    if (!\is_array($items)) {
        logs("get $mime_file mime.type content fail");
        return;
    }
    foreach ($items as $content) {
        if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) {
            $mime_type = $match[1];
            $workerman_file_extension_var = $match[2];
            $workerman_file_extension_array = \explode(' ', \substr($workerman_file_extension_var, 0, -1));
            foreach ($workerman_file_extension_array as $workerman_file_extension) {
                $mimeTypeMap[$workerman_file_extension] = $mime_type;
            }
        }
    }
}